package com.wei.czz.framework.common.service.impl;

import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.wei.czz.common.constant.EntityConstant;
import com.wei.czz.common.constant.RedisConstant;
import com.wei.czz.common.enums.CommonEnum;
import com.wei.czz.common.enums.ResultEnum;
import com.wei.czz.common.exception.CzzException;
import com.wei.czz.common.po.UserPo;
import com.wei.czz.common.utils.GuavaUtils;
import com.wei.czz.common.utils.SecurityUtils;
import com.wei.czz.framework.common.dao.FileImportDao;
import com.wei.czz.framework.common.entity.FileImportEntity;
import com.wei.czz.framework.common.service.FileImportService;
import lombok.AllArgsConstructor;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.util.CollectionUtils;

import java.util.*;

/**
 * Created by IntelliJ IDEA.
 *
 * @author wei
 * date: 2024-05-05 10:47:15
 * className: FileImportServiceImpl
 * version: 1.0
 * description:
 */
@Service("fileImportService")
@AllArgsConstructor
public class FileImportServiceImpl extends ServiceImpl<FileImportDao, FileImportEntity> implements FileImportService {

    private static final Logger log = LoggerFactory.getLogger(FileImportServiceImpl.class);

    private final RedissonClient redissonClient;

    @Override
    public Long saveOrEdit(FileImportEntity fileImport) {
        Long id = fileImport.getId();
        if (Objects.isNull(id)) {

            int count = baseMapper.insert(fileImport);
            log.info("保存文件上传记录完成。count={}", count);
        } else {
            // 修改
            int count = baseMapper.updateById(fileImport);
            log.info("修改文件上传记录完成。count={}", count);

            // 删除本地缓存
            GuavaUtils.remove(id.toString());
        }
        return id;
    }

    @Override
    public FileImportEntity get(Long id) {

        String redisKey = EntityConstant.FILE_IMPORT + RedisConstant.SPLIT + id;

        // 从缓存获取
        FileImportEntity fileImport = GuavaUtils.get(redisKey, FileImportEntity.class);
        if (Objects.nonNull(fileImport)) {
            log.info("从缓存中获取文件上传记录");
            return fileImport;
        }
        String lockKey = RedisConstant.LOCK + redisKey;
        RLock lock = redissonClient.getLock(lockKey);
        // 加锁
        lock.lock();

        try {
            // double check
            fileImport = GuavaUtils.get(redisKey, FileImportEntity.class);
            if (Objects.nonNull(fileImport)) {
                log.info("double check, 从缓存中获取文件上传记录");
                return fileImport;
            }

            fileImport = this.getFileImport(id);

            // 添加缓存
            GuavaUtils.set(redisKey, fileImport);

            return fileImport;
        } finally {
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                // 解锁
                lock.unlock();
            }
        }
    }

    @Override
    public List<FileImportEntity> getList(List<Long> idList) {
        if (CollectionUtils.isEmpty(idList)) {
            log.info("批量查询文件上传记录，传递的主键列表参数为空");
            return Collections.emptyList();
        }
        List<FileImportEntity> fileImportList = new ArrayList<>(idList.size());

        StringBuilder redisKeySb = new StringBuilder(EntityConstant.FILE_IMPORT + RedisConstant.SPLIT);
        int length = redisKeySb.length();

        Iterator<Long> iterator = idList.iterator();
        while (iterator.hasNext()) {
            Long id = iterator.next();
            // 获取缓存键
            String redisKey = redisKeySb.delete(length, redisKeySb.length()).append(id).toString();

            // 从缓存获取
            FileImportEntity fileImport = GuavaUtils.get(redisKey, FileImportEntity.class);
            if (Objects.nonNull(fileImport)) {
                // 记录结果
                fileImportList.add(fileImport);
                // 迭代器删除
                iterator.remove();
            }
        }
        if (idList.isEmpty()) {
            log.info("全部文件上传记录均从缓存中获取");
            fileImportList.sort(Comparator.comparing(FileImportEntity::getId));
            return fileImportList;
        }
        // 查询
        List<FileImportEntity> dbFileImportList = baseMapper.selectBatchIds(idList);
        log.info("查询文件上传记录完成。size={}", dbFileImportList.size());
        for (FileImportEntity fileImport : dbFileImportList) {
            // 获取缓存键
            String redisKey = redisKeySb.delete(length, redisKeySb.length()).append(fileImport.getId()).toString();
            // 添加缓存
            GuavaUtils.set(redisKey, fileImport);
            // 记录结果
            fileImportList.add(fileImport);
        }

        fileImportList.sort(Comparator.comparing(FileImportEntity::getId));
        return fileImportList;
    }

    @Override
    public void delete(List<Long> idList) {
        if (CollectionUtils.isEmpty(idList)) {
            log.info("删除文件上传记录，传递的主键列表为空");
            return;
        }
        // 获取操作用户
        UserPo userPo = SecurityUtils.getUser();
        Date date = new Date();

        LambdaUpdateWrapper<FileImportEntity> fileImportLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        fileImportLambdaUpdateWrapper.set(FileImportEntity::getDeleteStatus, CommonEnum.ONE.getValue())
                .set(FileImportEntity::getUpdateTime, date)
                .set(FileImportEntity::getUpdateUser, userPo.getUsername())
                .set(FileImportEntity::getUpdateUserId, userPo.getUserId());
        fileImportLambdaUpdateWrapper.in(FileImportEntity::getId, idList)
                .eq(FileImportEntity::getDeleteStatus, CommonEnum.ZERO.getValue());
        // 删除
        int count = baseMapper.update(fileImportLambdaUpdateWrapper);
        log.info("删除文件上传记录完成。count={}", count);
    }

    /**
     * 获取文件上传记录对象
     * @param id 主键
     * @return 文件上传记录对象
     */
    private FileImportEntity getFileImport(Long id) {
        FileImportEntity fileImport = baseMapper.selectById(id);
        if (Objects.isNull(fileImport)) {
            log.info("文件上传记录不存在");
            throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), "文件上传记录不存在，请确认。");
        }
        if (CommonEnum.ONE.getValue().equals(fileImport.getDeleteStatus())) {
            log.info("文件上传记录已删除");
            throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), "文件上传记录不存在，请确认。");
        }
        return fileImport;
    }
}